# -*-coding:utf-8-*-

""".
实现几何图形生成、几何计算、基于几何图形的地理化分析以及图形呈现
"""

import shapely.wkt
#import shapely.geometry
import shapely.geometry.point as point

from math import sin, asin, cos, radians, fabs, sqrt,pi

from pandas import DataFrame
from scipy.spatial import  Delaunay
from scipy.spatial import  Voronoi
import matplotlib.pyplot as plt

import numpy as np
import pandas as pd

class XY:
    """经纬度及其方法

    属性：
        x: float
        y: float
    """

    def __init__(self,x,y):
        self.x=x
        self.y=y

    def __repr__(self):
        return (str(tuple(zip(self.x,self.y))))


    def offset(self,azimuth,radius,crs=None):
        '''计算以某角度偏移一定距离后的经纬度

        :param azimuth: 方位角
        :param radius: 距离
        :param crs: 坐标系
        :return: 代表经纬度的数组
        '''

        x, y = (self.x,self.y)
        x1 = x + (radius * sin(azimuth * pi / 180)) / (111 * cos(y * pi / 180))
        y1 = y + (radius * cos(azimuth * pi / 180)) / 111
        return (x1, y1)

    def get_grid(self,size,type='wkt'):
        '''构造一个栅格几何图

        :param size: 栅格大小，int,20 代表20m*20m
        :param type:返回形式，{'wkt','geojson','polygon'} polygon代表__geo__interface__的polygon
        :return: 代表栅格的{'wkt','geojson','polygon'
        '''
        from shapely.geometry import geo
        radius=size* sqrt(2) / 1000
        azimuth=45
        x1, y1 = self.offset(radius=radius, azimuth=azimuth)
        grid=geo.box(self.x, self.y,x1,y1)
        if type=='wkt':
            return shapely.wkt.dumps(grid)
        elif type=='geojson':
            return shapely.geometry.mapping(grid)
        else:
            return grid


def show_voronoi(enbid=36922):
    if enbid in cellinfo['enbid'].values:
        s_type = cellinfo['sitetype'][cellinfo['enbid'] == enbid].values[0]
        if s_type.lower() == 'outdoor':
            pass
            #show enbid voronoi
    else:
        pass
        #show all voronoi


def jsonlist2jsondict(jsonlist):
    coordinates = []
    for j in jsonlist:
        if isinstance(j,str):
            coordinate = eval(j)['coordinates'][0]
        else:
            coordinate=j['coordinates'][0]
        coordinates.append(coordinate)
    return {'type': 'Polygon', 'coordinates': coordinates}


class Voronoi(Voronoi):
    '''重载Voronoi类'''

    def geojson(self):
        '''提供voronoi的几何图形'''
        voronoi_geojson = []
        i=-1
        for index_region in self.point_region:
            index_vertices = self.regions[index_region]
            index_vertices = np.asarray(index_vertices)
            i+=1
            if np.all(index_vertices >= 0):
                coor_vertices = self.vertices[index_vertices, :]
                polygon_geojson = {'coordinates': [coor_vertices.tolist()], 'type': 'Polygon'}
                voronoi_geojson.append((i,polygon_geojson))
            else:
                voronoi_geojson.append((i,''))
        return voronoi_geojson

class Delaunay(Delaunay):
    '''重载Delaunay类'''

    def nearest_cells(self):
        nei=[]
        for t in self.simplices:
            nei.append((t[0], t[1]))
            nei.append((t[0], t[2]))
            nei.append((t[1], t[2]))
        return nei

class VoronoiNRs4G:
    '''提供泰森多边形邻区相关功能'''

    NRsStructure = {
        'siteid_a': [],
        'siteid_b': [],
        'sitetype_a': [],
        'sitetype_b': [],
        'distance': [],
        'direction':[],
        'nei_type': [],
    }


    def __init__(self,cellinfo):
        '''输入cellinfo dataframe，包含eci/enbid/sitetype/longitude/latitude'''
        self.cellinfo=cellinfo
        if 'btsname_cn' in cellinfo.columns:
            siteinfo = cellinfo[['enbid', 'sitetype', 'longitude', 'latitude', 'btsname_cn']]
        else:
            siteinfo = cellinfo[['enbid', 'sitetype', 'longitude', 'latitude']]
        siteinfo=siteinfo.drop_duplicates(['enbid'])
        siteinfo['polygons']=''
        self.siteinfo=siteinfo

    @property
    def nrs(self):
        '''输出汇总'''
        nrs=self.outdoor_sites_nei()
        #******计算经纬度*****
        return  nrs

    @property
    def outdoor_sites(self):
        outdoor_sites_df=self.cellinfo[(self.cellinfo['sitetype'] == 'Outdoor') | (self.cellinfo['sitetype'] == 'outdoor')]
        outdoor_sites_df=outdoor_sites_df.drop_duplicates(['enbid'])
        return  outdoor_sites_df

    @property
    def indoor_sites(self):
        indoor_sites=self.cellinfo[(self.cellinfo['sitetype'] == 'Indoor') | (self.cellinfo['sitetype'] == 'indoor')]
        indoor_sites.drop_duplicates(['enbid'], inplace=True)
        return indoor_sites
    @property
    def samllcells(self):
        samllcells=self.cellinfo[(self.cellinfo['sitetype'] == 'Smallcell') | (self.cellinfo['sitetype'] == 'smallcell')]
        samllcells.drop_duplicates(['enbid'], inplace=True)
        return samllcells
    @property
    def polygons(self):
        
        pass

    def outdoor_sites_nei(self):
        outdoor_sites_nei: DataFrame=pd.DataFrame(VoronoiNRs4G.NRsStructure)

        # 调用delaunay生成邻区对
        outdoor_sites_df=self.outdoor_sites
        x,y,enbid=outdoor_sites_df['longitude'],outdoor_sites_df['latitude'],outdoor_sites_df['enbid']
        d = dict(zip(range(len(enbid)), enbid))
        points=np.array(list(zip(x, y)))
        delaunay_nei=Delaunay(points).nearest_cells()
        delaunay_nei = [[d[n[0]],d[n[1]]] for n in delaunay_nei]  #通过字典将邻区索引转换为enbid

        #整理成统一输出格式
        outdoor_sites_nei['siteid_a'],outdoor_sites_nei['siteid_b']=zip(*delaunay_nei)
        outdoor_sites_nei['sitetype_a'], outdoor_sites_nei['sitetype_b']='outdoor','outdoor'
        outdoor_sites_nei['direction'],outdoor_sites_nei['direction']='bidirection','circle1'

        #生成泰森多边形
        polygons=Voronoi(points).geojson()
        polygons={d[p[0]]:p[1] for p in polygons}
        #将geojson更新到siteinfo datafram中
        for index, row in self.siteinfo.iterrows():
            if (row['enbid'] in polygons) and (polygons[row['enbid']]!=''):
                self.siteinfo.at[index, 'polygons'] = polygons[row['enbid']]
        return outdoor_sites_nei




def get_distance(x1,y1,x2,y2):
    '''用haversine公式计算球面两点间的距离
    :return: int m
    '''
    EARTH_RADIUS = 6371  # 地球平均半径，6371km
    # 经纬度转换成弧度
    x1 = radians(x1)
    y1 = radians(y1)
    x2 = radians(x2)
    y2 = radians(y2)

    distance_x = fabs(x1 - x2)
    distance_y = fabs(y1 - y2)
    hav=lambda theta: sin(theta / 2)**2
    h = hav(distance_x) + cos(y1) * cos(y2) * hav(distance_y)
    distance = 2 * EARTH_RADIUS * asin(sqrt(h))*1000
    return distance


if __name__ == "__main__":
    import pandas as pd
    import numpy as np

    cellinfo = pd.read_csv(r'C:\Users\juyhe\Documents\JupyterNoteBook\data\cellinfo.csv', encoding='gbk')
    voronoinei = VoronoiNRs4G(cellinfo)
    nrs=voronoinei.nrs

